<template>
  <view :style="{ width: diam + 'px', height: (height || diam) + 'px' }" class="tui-circular-container">
    <canvas :canvas-id="progressCanvasId" :change:start="parse.initDraw" :class="[progressCanvasId]"
            :data-activeMode="activeMode"
            :data-cid="progressCanvasId" :data-counterclockwise="counterclockwise" :data-defaultColor="defaultColor"
            :data-defaultShow="defaultShow"
            :data-fontColor="getFontColor" :data-fontShow="fontShow" :data-fontSize="fontSize"
            :data-gradualColor="gradualColor" :data-height="height" :data-lineCap="lineCap"
            :data-lineWidth="lineWidth" :data-multiple="multiple" :data-percentText="percentText"
            :data-progressColor="getProgressColor" :data-sAngle="sAngle" :data-speed="speed" :data-width="diam"
            :start="percent" :style="{ width: diam + 'px', height: (height || diam) + 'px' }"></canvas>
    <slot></slot>
  </view>
</template>
<script lang="renderjs" module="parse">
export default {
  methods: {
    format(str) {
      if (!str) return str;
      return str.replace(/\"/g, "");
    },
    bool(str) {
      return str === 'true' || str == true ? true : false
    },
    //初始化绘制
    initDraw(percentage, oldPercentage, owner, ins) {
      let state = ins.getState();
      let res = ins.getDataset();
      const activeMode = this.format(res.activemode);
      let start = activeMode === 'backwards' ? 0 : (state.startPercentage || 0);
      //当start大于当前percentage时，start设置为0
      start = start > percentage ? 0 : start;
      if (!state.progressContext || !state.canvas) {
        const width = res.width;
        const height = res.height == 0 ? res.width : res.height;
        let ele = `.${res.cid}>canvas`
        const canvas = document.querySelectorAll(this.format(ele))[0];
        const ctx = canvas.getContext('2d');
        // const dpr =uni.getSystemInfoSync().pixelRatio;
        // canvas.style.width=width+'px';
        // canvas.style.height=height+'px';
        // canvas.width = width * dpr;
        // canvas.height = height * dpr;
        // ctx.scale(dpr, dpr);
        state.progressContext = ctx;
        state.canvas = canvas;
        this.drawProgressCircular(start, ctx, canvas, percentage, res, state, owner);
      } else {
        this.drawProgressCircular(start, state.progressContext, state.canvas, percentage, res, state, owner);
      }
    },
    //默认(背景)圆环
    drawDefaultCircular(ctx, canvas, res) {
      //终止弧度
      let sangle = Number(res.sangle) * Math.PI
      let eAngle = Math.PI * (res.height != 0 ? 1 : 2) + sangle;
      this.drawArc(ctx, eAngle, this.format(res.defaultcolor), res);
    },
    drawPercentage(ctx, percentage, res) {
      ctx.save(); //save和restore可以保证样式属性只运用于该段canvas元素
      ctx.beginPath();
      ctx.fillStyle = this.format(res.fontcolor);
      ctx.font = res.fontsize + "px Arial"; //设置字体大小和字体
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      let radius = res.width / 2;
      let percenttext = this.format(res.percenttext)
      if (!percenttext) {
        let multiple = Number(res.multiple)
        percentage = this.bool(res.counterclockwise) ? 100 - percentage * multiple : percentage * multiple;
        percentage = percentage.toFixed(0) + "%"
      } else {
        percentage = percenttext
      }
      ctx.fillText(percentage, radius, radius);
      ctx.stroke();
      ctx.restore();
    },
    //进度圆环
    drawProgressCircular(startPercentage, ctx, canvas, percentage, res, state, owner) {
      if (!ctx || !canvas) return;
      let that = this
      let gradient = ctx.createLinearGradient(0, 0, Number(res.width), 0);
      gradient.addColorStop(0, this.format(res.progresscolor));
      let gradualColor = this.format(res.gradualcolor)
      if (gradualColor) {
        gradient.addColorStop('1', gradualColor);
      }
      let requestId = null
      let renderLoop = () => {
        drawFrame((res) => {
          if (res) {
            requestId = requestAnimationFrame(renderLoop)
          } else {
            setTimeout(() => {
              cancelAnimationFrame(requestId)
              requestId = null;
              renderLoop = null;
            }, 20)
          }
        })
      }
      renderLoop()
      // requestId = requestAnimationFrame(renderLoop)

      function drawFrame(callback) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (that.bool(res.defaultshow)) {
          that.drawDefaultCircular(ctx, canvas, res)
        }
        if (that.bool(res.fontshow)) {
          that.drawPercentage(ctx, startPercentage, res);
        }
        let isEnd = percentage === 0 || (that.bool(res.counterclockwise) && startPercentage === 100);
        if (!isEnd) {
          let sangle = Number(res.sangle) * Math.PI
          let eAngle = ((2 * Math.PI) / 100) * startPercentage + sangle;
          that.drawArc(ctx, eAngle, gradient, res);
        }
        owner.callMethod('change', {
          percentage: startPercentage
        })
        if (startPercentage >= percentage) {
          state.startPercentage = startPercentage;
          owner.callMethod('end', {
            canvasId: that.format(res.canvasid)
          })
          callback && callback(false)
        } else {
          let num = startPercentage + Number(res.speed)
          startPercentage = num > percentage ? percentage : num;
          callback && callback(true)
        }
      }

    },
    //创建弧线
    drawArc(ctx, eAngle, strokeStyle, res) {
      ctx.save();
      ctx.beginPath();
      ctx.lineCap = this.format(res.linecap);
      ctx.lineWidth = Number(res.linewidth);
      ctx.strokeStyle = strokeStyle;
      let radius = res.width / 2; //x=y
      let sangle = Number(res.sangle) * Math.PI
      ctx.arc(radius, radius, radius - res.linewidth, sangle, eAngle, this.bool(res.counterclockwise));
      ctx.stroke();
      ctx.closePath();
      ctx.restore();
    }
  }
}
</script>
<script>
export default {
  name: 'tuiRoundProgress',
  emits: ['change', 'end'],
  props: {
    /*
      传值需使用rpx进行转换保证各终端兼容
      px = rpx / 750 * wx.getSystemInfoSync().windowWidth
      圆形进度条(画布)宽度，直径 [px]
    */
    diam: {
      type: Number,
      default: 60
    },
    //圆形进度条(画布)高度，默认取diam值[当画半弧时传值，height有值时则取height]
    height: {
      type: Number,
      default: 0
    },
    //进度条线条宽度[px]
    lineWidth: {
      type: Number,
      default: 4
    },
    /*
       线条的端点样式
       butt：向线条的每个末端添加平直的边缘
       round	向线条的每个末端添加圆形线帽
       square	向线条的每个末端添加正方形线帽
      */
    lineCap: {
      type: String,
      default: 'round'
    },
    //圆环进度字体大小 [px]
    fontSize: {
      type: Number,
      default: 12
    },
    //圆环进度字体颜色
    fontColor: {
      type: String,
      default: ''
    },
    //是否显示进度文字
    fontShow: {
      type: Boolean,
      default: true
    },
    /*
       自定义显示文字[默认为空，显示百分比，fontShow=true时生效]
       可以使用 slot自定义显示内容
      */
    percentText: {
      type: String,
      default: ''
    },
    //是否显示默认(背景)进度条
    defaultShow: {
      type: Boolean,
      default: true
    },
    //默认进度条颜色
    defaultColor: {
      type: String,
      default: '#CCC'
    },
    //进度条颜色
    progressColor: {
      type: String,
      default: ''
    },
    //进度条渐变颜色[结合progressColor使用，默认为空]
    gradualColor: {
      type: String,
      default: ''
    },
    //起始弧度，单位弧度 实际  Math.PI * sAngle
    sAngle: {
      type: Number,
      default: -0.5
    },
    //指定弧度的方向是逆时针还是顺时针。默认是false，即顺时针
    counterclockwise: {
      type: Boolean,
      default: false
    },
    //进度百分比 [10% 传值 10]
    percentage: {
      type: Number,
      default: 0
    },
    //进度百分比缩放倍数[使用半弧为100%时，则可传2]
    multiple: {
      type: Number,
      default: 1
    },
    //动画执行速度，值越大动画越快（0.1~100）
    speed: {
      type: [Number, String],
      default: 1
    },
    //backwards: 动画从头播；forwards：动画从上次结束点接着播
    activeMode: {
      type: String,
      default: 'backwards'
    }
  },
  computed: {
    getFontColor() {
      return this.fontColor || (uni && uni.$tui && uni.$tui.color.primary) || '#5677fc';
    },
    getProgressColor() {
      return this.progressColor || (uni && uni.$tui && uni.$tui.color.primary) || '#5677fc';
    }
  },
  watch: {
    percentage(val) {
      this.percent = val;
    }
  },
  mounted() {
    setTimeout(() => {
      this.percent = this.percentage;
    }, 50);
  },
  data() {
    return {
      percent: -1,
      progressCanvasId: this.getCanvasId()
    };
  },
  methods: {
    getCanvasId() {
      return 'tui' + new Date().getTime() + (Math.random() * 100000).toFixed(0);
    },
    change(e) {
      //绘制进度
      this.$emit('change', e);
    },
    end(e) {
      //绘制完成
      this.$emit('end', e);
    }
  }
};
</script>

<style scoped>
.tui-circular-container {
  position: relative;
}
</style>
